﻿//+-------------------------------------------------------------------------------------------------------------------------------------------------------
//
//Description: SqlDacApplicationViewModel
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using VmroleAuthor.Models;

namespace VmroleAuthor.ViewModels
{
    public class SqlDacApplicationViewModel : TreeViewItemViewModel, IAddScriptCommand, IAddSqlScriptCommand, IDataErrorInfo, IProduceValidationResults, IRemoveChildItem, ICanBeRemovedFromTree
    {
        private readonly VmRoleResourceExtensionViewModel vmRoleResourceExtensionViewModel;
        private readonly SQLDacApplication sqlDacApplication;
       
        private ReferencedApplicationPayloadViewModel sqlDacAppPackage;

        private StringParameterizableProperty deploymentName;
        private StringParameterizableProperty dacInstance;
        private EnumParameterizableProperty sqlAuthenticationType;
        private CredentialParameterizableProperty sqlDeploymentCredential;
        private BoolParameterizableProperty blockOnChanges;
        private BoolParameterizableProperty ignoreDataLoss;
        private BoolParameterizableProperty rollbackOnFailure;
        private StringParameterizableProperty sqlInstance;  
        private BoolParameterizableProperty skipPolicyValidation;
        private EnumParameterizableProperty uninstallMode;          
           

        public static class PropertyNames
        {
            public const string Summary = "Summary";
            public const string SqlDacAppPackage = "SqlDacAppPackage"; 
            public const string DeploymentName = "DeploymentName";
            public const string DacInstance = "DacInstance";
            public const string SqlAuthenticationType = "SqlAuthenticationType";
            public const string SqlDeploymentCredential = "SqlDeploymentCredential";
            public const string BlockOnChanges = "BlockOnChanges";
            public const string IgnoreDataLoss = "IgnoreDataLoss";
            public const string RollbackOnFailure = "RollbackOnFailure";
            public const string SqlInstance = "SqlInstance";
            public const string SkipPolicyValidation = "SkipPolicyValidation";
            public const string UninstallMode = "UninstallMode";       
        }

        public SqlDacApplicationViewModel(
            SQLDacApplication sqlDacApplication,
            ApplicationProfileViewModel applicationProfileViewModel,
            VmRoleResourceExtensionViewModel resourceExtensionViewModel)
            : base(applicationProfileViewModel, true)
        {
            if (sqlDacApplication == null)
            {
                sqlDacApplication = new SQLDacApplication();
            }
            this.sqlDacApplication = sqlDacApplication;
            this.vmRoleResourceExtensionViewModel = resourceExtensionViewModel;                       
            this.ValidationResults = new ObservableCollection<CloudServiceModelValidationResult>();
        }

        public SQLDacApplication SqlDacApplication
        {
            get { return this.sqlDacApplication; }
        }

        public string Summary
        {
            get
            {
               if (string.IsNullOrEmpty(this.sqlDacApplication.DeploymentName))
               {
                   return "SQL DAC";
               }
               return "SQL DAC (" + this.sqlDacApplication.DeploymentName + ")";
            }
        }

        public ReferencedApplicationPayloadViewModel SqlDacAppPackage
        {
            get
            {
                if (this.sqlDacAppPackage == null)
                {
                    Func<string> getter = () => this.sqlDacApplication.ApplicationPayloadId;
                    Action<string> setter = delegate(string value) { this.sqlDacApplication.ApplicationPayloadId = value; };
                    this.sqlDacAppPackage = new ReferencedApplicationPayloadViewModel(this.vmRoleResourceExtensionViewModel, ValidationHelper.PayloadType.SqlDac, getter, setter, true, PropertyNames.SqlDacAppPackage);
                }
                return this.sqlDacAppPackage;
            }
        }

        public StringParameterizableProperty DeploymentName
        {
            get
            {
                if (this.deploymentName == null)
                {                   
                    Func<string> paramValueGetter = () => this.sqlDacApplication.DeploymentName;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.DeploymentName = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.DeploymentName;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Deployment name"
                    };

                    this.deploymentName = new StringParameterizableProperty(
                        PropertyNames.DeploymentName,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "Deployment name",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.deploymentName;
            }          
        }

        public StringParameterizableProperty DacInstance
        {
            get
            {
                if (this.dacInstance == null)
                {                   
                    Func<string> paramValueGetter = () => this.sqlDacApplication.DacInstance;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.DacInstance = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.DacInstance;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "Dac Instance"
                        //TODO: default value
                    };

                    this.dacInstance = new StringParameterizableProperty(
                        PropertyNames.DacInstance,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "SQL DAC instance",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);                   
                }
                return this.dacInstance;
            }
        }

        /// <summary>
        /// SQLAuthenticationType      
        /// </summary>
        public EnumParameterizableProperty SqlAuthenticationType
        {
            get
            {
                if (this.sqlAuthenticationType == null)
                {
                    Func<string> paramValueGetter = () => this.sqlDacApplication.SQLAuthenticationType;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.SQLAuthenticationType = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.SqlAuthenticationType;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Option,
                        DefaultEnglishLabelText = "SQL authentication type",
                        Options = new List<string>(Enum.GetNames(typeof(SQLAuthenticationType)))
                    };

                    this.sqlAuthenticationType = new EnumParameterizableProperty(
                        PropertyNames.SqlAuthenticationType,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "SQL authentication type",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        typeof(SQLAuthenticationType),
                        false,
                        viewDefParamInfo
                        );
                }
                return this.sqlAuthenticationType;
            }
        }



        public CredentialParameterizableProperty SqlDeploymentCredential
        {
            get
            {
                if (this.sqlDeploymentCredential == null)
                {
                    Func<string> paramValueGetter = () => this.sqlDacApplication.SQLDeploymentCredential;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.SQLDeploymentCredential = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.SqlDeploymentCredential;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Credential,
                        DefaultEnglishLabelText = "SQL deployment credential"
                    };

                    this.sqlDeploymentCredential = new CredentialParameterizableProperty(
                        PropertyNames.SqlDeploymentCredential,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Credential,
                        "Sql deployment credential",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.sqlDeploymentCredential;
            }
        }


        /// <summary>
        /// bool
        /// </summary>   
        public BoolParameterizableProperty BlockOnChanges
        {
            get
            {
                if (this.blockOnChanges == null)
                {
                    Func<string> paramValueGetter = () => this.sqlDacApplication.BlockOnChanges;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.BlockOnChanges = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.BlockOnChanges;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultEnglishLabelText = "SQL DAC application block on changes",
                        DefaultInitialValue = "false"
                    };


                    this.blockOnChanges = new BoolParameterizableProperty(
                        PropertyNames.BlockOnChanges,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "SQL DAC application block on changes",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo
                        );
                }
                return this.blockOnChanges;
            }
        }

        /// <summary>
        /// bool
        /// </summary>   
        public BoolParameterizableProperty IgnoreDataLoss
        {
            get
            {
                if (this.ignoreDataLoss == null)
                {
                    Func<string> paramValueGetter = () => this.sqlDacApplication.IgnoreDataLoss;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.IgnoreDataLoss = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.IgnoreDataLoss;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultEnglishLabelText = "SQL DAC application ignore data loss",
                        DefaultInitialValue = "false"
                    };

                    this.ignoreDataLoss = new BoolParameterizableProperty(
                        PropertyNames.IgnoreDataLoss,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "SQL DAC application ignore data loss",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo);
                }
                return this.ignoreDataLoss;
            }
        }

        /// <summary>
        /// bool
        /// </summary>   
        public BoolParameterizableProperty RollbackOnFailure
        {
            get
            {
                if (this.rollbackOnFailure == null)
                {
                    Func<string> paramValueGetter = () => this.sqlDacApplication.RollbackOnFailure;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.RollbackOnFailure = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.RollbackOnFailure;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultEnglishLabelText = "SQL DAC application roll back on failure",
                        DefaultInitialValue = "true"
                    };

                    this.rollbackOnFailure = new BoolParameterizableProperty(
                        PropertyNames.RollbackOnFailure,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "SQL DAC application roll back on failure",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.rollbackOnFailure;
            }
        }      

        public StringParameterizableProperty SqlInstance
        {
            get
            {
                if (this.sqlInstance == null)
                {                  
                    Func<string> paramValueGetter = () => this.sqlDacApplication.SQLInstance;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.SQLInstance = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.SqlInstance;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.String,
                        DefaultEnglishLabelText = "SQL Instance",
                        DefaultInitialValue = "MSSQLSERVER"
                    };

                    this.sqlInstance = new StringParameterizableProperty(
                        PropertyNames.SqlInstance,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "SQL instance",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        false,
                        viewDefParamInfo); 
                }
                return this.sqlInstance;
            }
        }

        /// <summary>
        /// bool
        /// </summary>   
        public BoolParameterizableProperty SkipPolicyValidation
        {
            get
            {
                if (this.skipPolicyValidation == null)
                {
                    Func<string> paramValueGetter = () => this.sqlDacApplication.SkipPolicyValidation;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.SkipPolicyValidation = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.SkipPolicyValidation;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Boolean,
                        DefaultEnglishLabelText = "SQL DAC application skip policy validation",
                        DefaultInitialValue = "false"
                    };

                    this.skipPolicyValidation = new BoolParameterizableProperty(
                        PropertyNames.SkipPolicyValidation,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.Boolean,
                        "SQL DAC application skip policy validation",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        true,
                        viewDefParamInfo);
                }
                return this.skipPolicyValidation;
            }
        }


        /// <summary>
        /// SQLAuthenticationType      
        /// </summary>
        public EnumParameterizableProperty UninstallMode
        {
            get
            {
                if (this.uninstallMode == null)
                {
                    Func<string> paramValueGetter = () => this.sqlDacApplication.UninstallMode;
                    Action<string> paramValueSetter = delegate(string value) { this.sqlDacApplication.UninstallMode = value; };
                    Func<string> autoParamNameGetter = () => PropertyNames.UninstallMode;
                    ViewDefParamInfo viewDefParamInfo = new ViewDefParamInfo
                    {
                        ViewDefParameterType = ViewDefParameterType.Option,
                        DefaultEnglishLabelText = "SQL DAC application uninstall mode",
                        Options = new List<string>(Enum.GetNames(typeof(DACUninstallModeType)))
                    };

                    this.uninstallMode = new EnumParameterizableProperty(
                        PropertyNames.UninstallMode,
                        paramValueGetter,
                        paramValueSetter,
                        autoParamNameGetter,
                        ParameterType.String,
                        "SQL DAC UninstallMode",
                        this.vmRoleResourceExtensionViewModel.ResourceExtensionParametersViewModel,
                        typeof(DACUninstallModeType),
                        true,
                        viewDefParamInfo
                        );
                }
                return this.uninstallMode;
            }
        }

      
        public bool CanAddScriptCommand
        {
            get { return true; }
        }

        public void AddScriptCommand()
        {
            this.IsExpanded = true;
            if (this.sqlDacApplication.ScriptCommands == null)
            {
                this.sqlDacApplication.ScriptCommands = new List<ProvisioningScript>();
            }

            ProvisioningScript scriptCommand = new ProvisioningScript();
            scriptCommand.ExecutableAndParams = new ExecutableAndParams();
            this.sqlDacApplication.ScriptCommands.Add(scriptCommand);
            var scriptCommandViewModel = new ProvisioningScriptViewModel(scriptCommand, this, this.vmRoleResourceExtensionViewModel);
            this.Children.Add(scriptCommandViewModel);
            scriptCommandViewModel.IsSelected = true;
        }

        public bool CanAddSqlScriptCommand
        {
            get { return true; }
        }

        public void AddSqlScriptCommand()
        {
            this.IsExpanded = true;
            if (this.sqlDacApplication.SQLScriptCommands == null)
            {
                this.sqlDacApplication.SQLScriptCommands = new List<SQLScriptCommand>();
            }

            SQLScriptCommand scriptCommand = new SQLScriptCommand();          
            this.sqlDacApplication.SQLScriptCommands.Add(scriptCommand);
            var sqlScriptCommandViewModel = new SqlScriptViewModel(scriptCommand, this, this.vmRoleResourceExtensionViewModel);
            this.Children.Add(sqlScriptCommandViewModel);
            sqlScriptCommandViewModel.IsSelected = true;            
        }

        protected override void LoadChildren()
        {
            if (this.sqlDacApplication.ScriptCommands != null)
            {
                foreach (ProvisioningScript provisioningScript in this.sqlDacApplication.ScriptCommands)
                {
                    this.Children.Add(new ProvisioningScriptViewModel(provisioningScript, this, this.vmRoleResourceExtensionViewModel));
                }
            }
            if (this.sqlDacApplication.SQLScriptCommands != null)
            {
                foreach (SQLScriptCommand script in this.sqlDacApplication.SQLScriptCommands)
                {
                    this.Children.Add(new SqlScriptViewModel(script, this, this.vmRoleResourceExtensionViewModel));
                }
            }            
        }

        public void RemoveChild(TreeViewItemViewModel childItem)
        {
            var provisioningScriptViewModel = childItem as ProvisioningScriptViewModel;
            if (provisioningScriptViewModel != null)
            {
                provisioningScriptViewModel.Cleanup();
                this.sqlDacApplication.ScriptCommands.Remove(provisioningScriptViewModel.ProvisioningScript);
                this.Children.Remove(childItem);
                return;
            }
            var sqlScriptViewModel = childItem as SqlScriptViewModel;
            if (sqlScriptViewModel != null)
            {
                sqlScriptViewModel.Cleanup();
                this.sqlDacApplication.SQLScriptCommands.Remove(sqlScriptViewModel.SQLScriptCommand);
                this.Children.Remove(childItem);
            }
        }

        public void Cleanup()
        {
            this.IsExpanded = true;
            ParametersAndPayloadCleanupHelper.CleanupParametersAndPayload(this, typeof(PropertyNames));
        }

        public string this[string propertyName]
        {
            get
            {
                string error = null;
                switch (propertyName)
                {
                    case PropertyNames.DeploymentName:
                        error = ValidationHelper.ValidateNotNullOrEmpty(this.sqlDacApplication.DeploymentName) ??
                                ValidationHelper.ValidateApplicationDeploymentNamesAreUnique(this.vmRoleResourceExtensionViewModel.ResourceExtensionDefinition);
                        break;
                }
                return error;               
            }           
        }

        public string Error { get; set; }

        public ObservableCollection<CloudServiceModelValidationResult> ValidationResults { get; private set; }

        public void UpdateValidationResults()
        {
            this.IsExpanded = true;
            ModelValidationResultsHelper.UpdateValidationResults(this, typeof(PropertyNames));
            //Add any other cross-field validations error            
        }       
    }
}
